﻿#include "FITKAcousticsVTKGraphObjectSEAJunctionLine.h"
#include "FITKAcousticsVTKGraphActor.h"

// VTK
#include <vtkProperty.h>
#include <vtkUnstructuredGrid.h>
#include <vtkPoints.h>
#include <vtkTubeFilter.h>
#include <vtkDataSetSurfaceFilter.h>

// App
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"

// Data
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsSEAModel.h"
#include "FITK_Component/FITKAcousticsModel/FITKAcousticsDiscNodeList.h"
#include "FITK_Component/FITKAcousticsModel/FITKSEAJunctionLine.h"

// Graph and filter
#include "FITKAcousticsVTKCommons.h"
#include "FITKAcousticsVTKSharedDataManager.h"
#include "FITKAcousticsVTKGraphObjectSelect.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"

namespace Exchange
{
    FITKAcousticsVTKGraphObjectSEAJunctionLine::FITKAcousticsVTKGraphObjectSEAJunctionLine(Acoustics::FITKSEAJunctionLine* jLine)
        : FITKAcousticsVTKGraphObjectSEAJunction(jLine)
    {
        // Return if the input is nullptr.
        if (!jLine)
        {
            return;
        }

        // Intiailize the polygon offset.
        m_polygonOffset = FITKAcousticsVTKCommons::s_polygonOffsetSEAJunction;

        // Initialize the vtk object.
        init();

        // Generate the data set.
        if (!generateDataSet(jLine))
        {
            return;
        }

        // Generate the nodes actor.
        generateGraph();

        // Update the visibility.
        updateVisibility();

        // Save the data type.
        m_graphInfo.Type = FITKAcousticsVTKCommons::JunctionLine;
    }

    FITKAcousticsVTKGraphObjectSEAJunctionLine::~FITKAcousticsVTKGraphObjectSEAJunctionLine()
    {
        // Delete the vtk object.
        deleteVtkObj(m_tubeFilter);
    }

    void FITKAcousticsVTKGraphObjectSEAJunctionLine::init()
    {
        this->Superclass::init();

        // Initialize the tube filter and surface filter.
        vtkSmartPointer<vtkDataSetSurfaceFilter> surfFilter = vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
        surfFilter->SetInputData(m_ugrid);

        m_tubeFilter = vtkTubeFilter::New();
        m_tubeFilter->SetCapping(true);
        m_tubeFilter->SetNumberOfSides(30);
        m_tubeFilter->SetSidesShareVertices(true);
        m_tubeFilter->SetInputConnection(surfFilter->GetOutputPort());
    }

    void FITKAcousticsVTKGraphObjectSEAJunctionLine::updateVisibility()
    {
        // Get the runtime settings for visibility.
        bool showJunc = getGlobalSEAJunctionsVisibility();
        bool showJLines = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_JUNCTION_LINES, true);
        bool showSEAJLines = getRuntimeSettingAs<bool>(RTS_KEY_VISIBLE_SEA_JUNC_LINES, true);
        bool mainFlag = FITKAcousticsVTKGraphObject3D::getDataVisibility() && showJunc && showJLines && showSEAJLines;

        // Update the visibility with the flags.
        //@{
        // Show or hide actors.
        setVisible(mainFlag);
        //@}
    }

    bool FITKAcousticsVTKGraphObjectSEAJunctionLine::generateDataSet(Acoustics::FITKAbstractJunction* junction)
    {
        if (!m_points || !m_ugrid)
        {
            return false;
        }

        Acoustics::FITKSEAJunctionLine* jLine = dynamic_cast<Acoustics::FITKSEAJunctionLine*>(junction);
        if (!jLine)
        {
            return false;
        }

        // Get the SEA node list.
        Acoustics::FITKAcousticsDiscNodeList* seaNodes = getSEANodesData();
        if (!seaNodes)
        {
            return false;
        }

        // Get the junction points of the line.
        QList<int> ids = jLine->getPoints();
        for (const int & id : ids)
        {
            double pos3[3]{ 0., 0., 0. };
            bool flag = FITKAcousticsVTKCommons::GetSEANodePositionById(seaNodes, id, pos3);
            Q_UNUSED(flag);
            
            m_points->InsertNextPoint(pos3);
        }

        // Generate the poly line cell.
        vtkSmartPointer<vtkIdList> cell = vtkSmartPointer<vtkIdList>::New();
        for (int i = 0; i < m_points->GetNumberOfPoints(); i++)
        {
            cell->InsertNextId(i);
        }

        m_ugrid->InsertNextCell(VTKCellType::VTK_POLY_LINE, cell);

        // Update the tube radius.
        updateGlyphSizeByRatio();

        return true;
    }

    void FITKAcousticsVTKGraphObjectSEAJunctionLine::generateGraph()
    {
        // Initialize color.
        Acoustics::FITKSEAAbstractJunction* junction = dynamic_cast<Acoustics::FITKSEAAbstractJunction*>(_dataObj);
        if (!junction)
        {
            return;
        }

        // Create glyph actor.
        m_fActor = FITKAcousticsVTKGraphActor::New();
        m_fActor->setGraphObject(this);
        m_fActor->setActorType(ActorType::VertexActor);
        m_fActor->SetPickable(false);
        m_fActor->SetVisibility(true);
        m_fActor->GetProperty()->SetRepresentation(2);
        m_fActor->GetProperty()->SetPointSize(0.);
        m_fActor->GetProperty()->SetLineWidth(1.);
        // m_fActor->GetProperty()->SetRenderLinesAsTubes(true);
        m_fActor->GetProperty()->SetEdgeVisibility(false);
        m_fActor->setRelativeCoincidentTopologyPolygonOffsetParameters(m_polygonOffset);
        addActor(m_fActor);

        // Set the input connection.
        m_fActor->setInputConnection(m_tubeFilter->GetOutputPort());
        
        // Update color by enable flag.
        updateColorByEnableFlag();
    }

    void FITKAcousticsVTKGraphObjectSEAJunctionLine::updateGlyphSizeByRatio()
    {
        if (!m_tubeFilter)
        {
            return;
        }

        // Calculate the glyph size.
        m_tubeRadius = FITKAcousticsVTKSharedDataManager::GetInstance()->getTubeWorldSizeByRatio();
        m_tubeFilter->SetRadius(m_tubeRadius);

        // Update the pipeline.
        m_tubeFilter->Update();
    }
}   // namespace Exchange